//===============================================================================
// Microsoft patterns & practices Enterprise Library Contribution
// Validation Application Block
//===============================================================================
// Code file original author: Martin Lapierre, http://devinstinct.com
//===============================================================================

using System;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Common;
using EntLibContrib.Validation.Validators;

namespace EntLibContrib.Validation.Configuration
{
	/// <summary>
	/// Configuration object to describe an instance of class <see cref="TypeValidatorData"/>.
	/// </summary>
	/// <remarks>
	/// Spin-off of the TypeConversionValidatorData class.
	/// </remarks>
	public class TypeValidatorData : ValueValidatorData
	{
		#region Constants
		private const string TargetTypeNamePropertyName = "targetType";
		#endregion

		#region Fields
		private static readonly AssemblyQualifiedTypeNameConverter typeConverter = new AssemblyQualifiedTypeNameConverter();
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets name of the type the represented <see cref="TypeValidator{T}"/> must use for testing conversion.
		/// </summary>
		/// <value>The name of the target type.</value>
		[ConfigurationProperty(TargetTypeNamePropertyName, IsRequired = true)]
		public string TargetTypeName
		{
			get { return (string)this[TargetTypeNamePropertyName]; }
			set { this[TargetTypeNamePropertyName] = value; }
		}

		/// <summary>
		/// Gets or sets the target element type.
		/// </summary>
		/// <value>The type of the target.</value>
		public Type TargetType
		{
			get { return (Type)typeConverter.ConvertFrom(TargetTypeName); }
			set { TargetTypeName = typeConverter.ConvertToString(value); }
		}
		#endregion

		#region Construction
		/// <summary>
		/// <para>Initializes a new instance of the <see cref="TypeValidatorData"/> class.</para>
		/// </summary>
		public TypeValidatorData()
		{ }

		/// <summary>
		/// <para>Initializes a new instance of the <see cref="TypeValidatorData"/> class with a name.</para>
		/// </summary>
		/// <param name="name">The name for the instance.</param>
		public TypeValidatorData(string name)
			: base(name, typeof(TypeValidator<>))
		{ }
		#endregion

		#region Protected Methods
		/// <summary>
		/// Creates the <see cref="TypeValidator{T}"/> described by the configuration object.
		/// </summary>
		/// <param name="targetType">Not used.</param>
		/// <returns>
		/// The created <see cref="TypeValidator{T}"/>.
		/// </returns>
		/// <remarks>This operation must be overriden by subclasses.</remarks>
		protected override Validator DoCreateValidator(Type targetType)
		{
			Type typeValidator = typeof(TypeValidator<>).MakeGenericType(TargetType);
			return Activator.CreateInstance(typeValidator, GetMessageTemplate(), Tag, Negated) as Validator;
		}
		#endregion

		#region Private Methods
		/// <summary>
		/// Returns the message template for the represented validator.
		/// </summary>
		/// <returns></returns>
		/// <remarks>
		/// Same as ValidatorData::GetMessageTemplate... internal
		/// The textual message is given precedence over the resource based mechanism.
		/// </remarks>
		private new string GetMessageTemplate()
		{
			if (!string.IsNullOrEmpty(this.MessageTemplate))
			{
				return this.MessageTemplate;
			}
			Type messageTemplateResourceType = this.GetMessageTemplateResourceType();
			if (null != messageTemplateResourceType)
			{
				return ResourceStringLoader.LoadString(messageTemplateResourceType.FullName,
						this.MessageTemplateResourceName,
						messageTemplateResourceType.Assembly);
			}

			return null;
		}

		/// <summary>
		/// Same as ValidatorData::GetMessageTemplateResourceType... private
		/// </summary>
		/// <returns></returns>
		private Type GetMessageTemplateResourceType()
		{
			if (!string.IsNullOrEmpty(this.MessageTemplateResourceTypeName))
			{
				return Type.GetType(this.MessageTemplateResourceTypeName);
			}

			return null;
		}
		#endregion
	}
}
